package com.zw.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zw.constant.Constants;
import com.zw.constant.MessageConstant;
import com.zw.core.domain.entity.SysUser;
import com.zw.core.domain.model.LoginUser;
import com.zw.dto.UserForgotDto;
import com.zw.dto.UserLoginDto;
import com.zw.dto.UserRegisterDto;
import com.zw.enumeration.UserStatus;
import com.zw.exception.ServiceException;
import com.zw.exception.base.BaseException;
import com.zw.exception.user.UserNotExistsException;
import com.zw.exception.user.UserPasswordNotMatchException;
import com.zw.manager.AsyncManager;
import com.zw.manager.factory.AsyncFactory;
import com.zw.mapper.SysUserMapper;
import com.zw.service.ISysUserService;
import com.zw.service.UserService;
import com.zw.utils.DateUtils;
import com.zw.utils.MailUtil;
import com.zw.utils.MessageUtils;
import com.zw.utils.SecurityUtils;
import com.zw.utils.ip.IpUtils;
import com.zw.vo.UserLoginVo;
import com.zw.web.service.TokenService;
import jakarta.annotation.Resource;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements UserService {

    @Resource
    private MailUtil mailUtil;
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private TokenService tokenService;
    @Resource
    private ISysUserService userService;

    @Override
    public boolean register(UserRegisterDto userRegisterDto) {
        SysUser sysUser = BeanUtil.copyProperties(userRegisterDto, SysUser.class);
        LambdaUpdateWrapper<SysUser> wq = new LambdaUpdateWrapper<>();
        wq.eq(SysUser::getEmail, sysUser.getEmail());
        wq.eq(SysUser::getActivate, 1);
        if (this.count(wq) > 0) {
            throw new BaseException(MessageConstant.EMAIL_EXIST);
        }
        baseMapper.deleteByEmail(sysUser.getEmail());

        sysUser.setPassword(SecurityUtils.encryptPassword(sysUser.getPassword()));
        sysUser.setUserType("01");
        sysUser.setNickName(sysUser.getUserName());
        baseMapper.insertUser(sysUser);

        return mailUtil.sendEmailActivate(
                "http://gaokao.ltd/user/user/activate?username=" + sysUser.getUserName() + "&email=" + sysUser.getEmail(),
                sysUser.getUserName(),
                sysUser.getEmail(),
                DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"),
                sysUser.getEmail()
        );
    }


    @Override
    public boolean activate(String username, String email) {
        SysUser sysUser = baseMapper.getUserByEmail(email);
        if (Objects.nonNull(sysUser)) {
            sysUser.setActivate(1);
            return this.updateById(sysUser);
        }
        return false;
    }

    @Override
    public UserLoginVo login(UserLoginDto userLoginDto) {
        SysUser sysUser = baseMapper.getUserByEmailAndActivate(userLoginDto.getEmail());
        if (Objects.isNull(sysUser)) {
            throw new UserNotExistsException();
        }

        if (!SecurityUtils.matchesPassword(userLoginDto.getPassword(), sysUser.getPassword())) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }

        if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())){
            throw new ServiceException(MessageUtils.message("user.blocked"));
        }

        LoginUser loginUser = new LoginUser(sysUser.getUserId(), sysUser.getDeptId(), sysUser, null);
        // 记录登录信息
        recordLoginInfo(loginUser.getUserId());
        // 生成token
        String serviceToken = tokenService.createToken(loginUser);
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(sysUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        return UserLoginVo.builder()
                .token(serviceToken)
                .company(sysUser.getCompany())
                .nickName(sysUser.getNickName())
                .avatar(sysUser.getAvatar())
                .email(sysUser.getEmail())
                .userId(sysUser.getUserId())
                .sex(sysUser.getSex())
                .phonenumber(sysUser.getPhonenumber())
                .build();
    }

    @Override
    public boolean forgot(UserForgotDto userForgotDto) {

        Boolean aBoolean = redisTemplate.hasKey("emailCode:" + userForgotDto.getEmail());

        if (aBoolean == null || !aBoolean) {
            throw new BaseException(MessageConstant.CODE_EXPIRED);
        }

        SysUser sysUser = baseMapper.getUserByEmailAndActivate(userForgotDto.getEmail());
        if (Objects.isNull(sysUser)) {
            throw new BaseException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        sysUser.setPassword(SecurityUtils.encryptPassword(userForgotDto.getPassword()));
        return baseMapper.updateById(sysUser) > 0;
    }

    @Override
    public boolean sendCode(String email) {
        int code = RandomUtil.randomInt(100000, 1000000);
        boolean b = mailUtil.sendEmailCode(String.valueOf(code), email);
        redisTemplate.opsForValue().set("emailCode:" + email, code, 5 * 60 * 1000, TimeUnit.MILLISECONDS);
        return b;
    }


    @Override
    public UserLoginVo getUserInfo() {
        Long userId = SecurityUtils.getUserId();
        SysUser sysUser = baseMapper.selectById(userId);
        return BeanUtil.copyProperties(sysUser, UserLoginVo.class);
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
}
